package com.csust.automaticteach.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.csust.automaticteach.common.BaseResponse;
import com.csust.automaticteach.common.ResultUtils;
import com.csust.automaticteach.model.enums.GeneratePptStatusEnum;
import com.csust.automaticteach.exception.BusinessException;
import com.csust.automaticteach.exception.ErrorCode;
import com.csust.automaticteach.exception.ThrowUtils;
import com.csust.automaticteach.app.teacher.iflytek.ppt.ApiClient;
import com.csust.automaticteach.app.teacher.iflytek.ppt.model.vo.CreateResponse;
import com.csust.automaticteach.app.teacher.iflytek.ppt.model.vo.ProgressResponse;
import com.csust.automaticteach.model.dto.generateppt.*;
import com.csust.automaticteach.model.entity.GeneratePpt;
import com.csust.automaticteach.model.entity.User;
import com.csust.automaticteach.model.vo.generateppt.GeneratePptVO;
import com.csust.automaticteach.model.vo.generateppt.TemplateVO;
import com.csust.automaticteach.model.vo.generateppt.TemplateVOWithDetailImage;
import com.csust.automaticteach.model.vo.generateppt.response.CheckProgressVO;
import com.csust.automaticteach.model.vo.generateppt.response.TemplateResponse;
import com.csust.automaticteach.service.GeneratePptService;
import com.csust.automaticteach.service.UserService;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Schedulers;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import static com.csust.automaticteach.constant.AppPromptConstant.PROMPT_TEMPLATE;

/**
 * @ClassNameGeneratePPTController
 * @Description 生成ppt的controller
 * @Author钰玟
 * @Date2025/7/17 下午11:50
 * @Version 1.0
 **/
@RestController
@RequestMapping("/generatePPT")
@Slf4j
public class GeneratePPTController {
    @Resource
    private ApiClient apiClient;
    @Resource
    private UserService userService;
    @Resource
    private GeneratePptService generatePptService;
    /**
     *  获取ppt模板列表
     * @param themeTemplateQueryRequest 模板查询参数
     * @return 模板列表
     * @throws IOException 创建接口异常
     */
    @PostMapping("/list/template")
    public BaseResponse<TemplateVOWithDetailImage> getTemplateList(@RequestBody ThemeTemplateQueryRequest themeTemplateQueryRequest) throws IOException {
        log.info("获取ppt模板列表:{}", themeTemplateQueryRequest);
        String templateList = apiClient.getTemplateList(themeTemplateQueryRequest);
        TemplateResponse templateResponse = JSONUtil.toBean(templateList, TemplateResponse.class);
        //提取 数据
        TemplateResponse.Data data = templateResponse.getData();
        TemplateVO templateVO = new TemplateVO();
        BeanUtil.copyProperties(data, templateVO);
        //处理后的 detailImage
        List<TemplateVO.ThemeRecord> list = templateVO.getRecords().stream().map(
                record -> {
                    List<String> imageList = new ArrayList<>();
                    String detailImageJson = record.getDetailImage();
                    TemplateVO.ImageDetail bean = JSONUtil.toBean(detailImageJson, TemplateVO.ImageDetail.class);
                    String titleCoverImageLarge = bean.getTitleCoverImageLarge();
                    String titleCoverImage = bean.getTitleCoverImage();
                    String catalogueCoverImage = bean.getCatalogueCoverImage();
                    String chapterCoverImage = bean.getChapterCoverImage();
                    String contentCoverImage = bean.getContentCoverImage();
                    String endCoverImage = bean.getEndCoverImage();
                    imageList.add(titleCoverImageLarge);
                    imageList.add(titleCoverImage);
                    imageList.add(catalogueCoverImage);
                    imageList.add(chapterCoverImage);
                    imageList.add(contentCoverImage);
                    imageList.add(endCoverImage);
                    record.setImageList(imageList);
                    return record;
                }
        ).toList();
        templateVO.setRecords(list);
        TemplateVOWithDetailImage templateVOWithDetailImage = new TemplateVOWithDetailImage();
        BeanUtil.copyProperties(templateVO, templateVOWithDetailImage);
        return ResultUtils.success(templateVOWithDetailImage);
    }
    /**
     * 通过上传自定义大纲得到ppt大纲
     *
     * @param  generatePPTRequest 自定义大纲请求
     * @param request 请求
     * @return genPptId
     */
    @PostMapping("/generate/query")
    public BaseResponse<Long> generatePPTOutlineByUploadOutline(@RequestBody GeneratePPTRequest generatePPTRequest
            , HttpServletRequest request){
        ThrowUtils.throwIf(generatePPTRequest == null, ErrorCode.PARAMS_ERROR);
        User loginUser = userService.getLoginUser(request);
        //拼接提示词
        String oldQuery = generatePPTRequest.getQuery();
        String newQuery = String.format(PROMPT_TEMPLATE+"参考材料如下：%s", oldQuery);
        generatePPTRequest.setQuery(newQuery);
        //发送请求并得到执行结果
        String outlineByQuery = null;
        try {
            outlineByQuery = apiClient.createOutlineByQuery(generatePPTRequest);
        } catch (IOException e) {
            log.error("创建大纲失败");
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "创建大纲失败");
        }
        //1.2 反序列化为对象
        CreateResponse outlineResponse = JSONUtil.toBean(outlineByQuery, CreateResponse.class);
        //1.3 提取 outline title coverImgSrc
        String title = "标题";
        String outline = outlineResponse.getData().getOutline();
        title = outlineResponse.getData().getTitle();
        GeneratePpt generatePpt = new GeneratePpt();
        generatePpt.setOutline(outline);
        generatePpt.setTitle(title);
        generatePpt.setUserName(loginUser.getUserName());
        generatePpt.setStatus(5);
        boolean saved = generatePptService.save(generatePpt);
        ThrowUtils.throwIf(!saved, ErrorCode.OPERATION_ERROR);
        Long id = generatePpt.getId();
        return ResultUtils.success(id);
    }

    /**
     * 通过上传文件得到ppt大纲
     *
     * @param multipartFile 上传的文件
     * @param request 请求
     * @return genPptId
     * @throws IOException 文件操作异常
     */
    @PostMapping("/generate/file")
    public BaseResponse<Long> generatePPTOutlineByUploadFile(@RequestPart("file") MultipartFile multipartFile
            , HttpServletRequest request) throws IOException {
        User loginUser = userService.getLoginUser(request);
        String uploadPath = System.getProperty("user.dir") + "/tmp/generate";
        String fileName = multipartFile.getOriginalFilename();
        File dest = FileUtil.file(uploadPath, fileName);
        FileUtil.mkdir(uploadPath);
        // 创建目录并写文件
        multipartFile.transferTo(dest);
        File outlineFile = new File(dest.getAbsolutePath());//根据文档生成大纲
            String outlineByDoc = null;
            try {
                //1. 生成ppt的大纲
                //1.1创建大纲请求对象
                GetOutlineRequest getOutlineRequest = new GetOutlineRequest();
                getOutlineRequest.setFile(outlineFile);
                getOutlineRequest.setFileName(outlineFile.getName());
                getOutlineRequest.setQuery(PROMPT_TEMPLATE);
                outlineByDoc = apiClient.createOutlineByDoc(getOutlineRequest);
                log.info("创建大纲结果：{}", outlineByDoc);
            } catch (Exception e) {
                throw new RuntimeException(e);
            } finally {
                FileUtil.del(outlineFile);
            }
            //1.2 反序列化为对象
            CreateResponse outlineResponse = JSONUtil.toBean(outlineByDoc, CreateResponse.class);
        //1.3 提取 outline title coverImgSrc
            String title = "标题";
            String outline = outlineResponse.getData().getOutline();
            title = outlineResponse.getData().getTitle();
            GeneratePpt generatePpt = new GeneratePpt();
            generatePpt.setOutline(outline);
            generatePpt.setTitle(title);
            generatePpt.setUserName(loginUser.getUserName());
            generatePpt.setStatus(5);
            boolean saved = generatePptService.save(generatePpt);
            ThrowUtils.throwIf(!saved, ErrorCode.OPERATION_ERROR);
            Long id = generatePpt.getId();
            return ResultUtils.success(id);
    }
    /**
     * 通过文件url 得到ppt大纲
     *
     * @param  generatePPTRequest 自定义大纲请求
     * @param request 请求
     * @return genPptId
     */
    @PostMapping("/generate/file_url")
    public BaseResponse<Long> generatePPTOutlineByFileUrl(@RequestBody GeneratePPTRequest generatePPTRequest
            , HttpServletRequest request){
        ThrowUtils.throwIf(generatePPTRequest == null, ErrorCode.PARAMS_ERROR);
        User loginUser = userService.getLoginUser(request);
        //发送请求并得到执行结果
        String outlineByQuery = null;
        //构建请求参数
        GetOutlineRequest getOutlineRequest = new GetOutlineRequest();
        getOutlineRequest.setFileUrl(generatePPTRequest.getFileUrl());
        try {
            outlineByQuery = apiClient.createOutlineByDoc(getOutlineRequest);
        } catch (IOException e) {
            log.error("创建大纲失败");
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "创建大纲失败");
        }
        //1.2 反序列化为对象
        CreateResponse outlineResponse = JSONUtil.toBean(outlineByQuery, CreateResponse.class);
        //1.3 提取 outline title coverImgSrc
        String title = "标题";
        String outline = outlineResponse.getData().getOutline();
        title = outlineResponse.getData().getTitle();
        GeneratePpt generatePpt = new GeneratePpt();
        generatePpt.setOutline(outline);
        generatePpt.setTitle(title);
        generatePpt.setUserName(loginUser.getUserName());
        generatePpt.setStatus(5);
        boolean saved = generatePptService.save(generatePpt);
        ThrowUtils.throwIf(!saved, ErrorCode.OPERATION_ERROR);
        Long id = generatePpt.getId();
        return ResultUtils.success(id);
    }

    /**
     * 生成ppt
     * @param generatePPTAddRequest 生成ppt请求
     * @param request 请求
     * @return 生成ppt的任务id sid
     */
    @PostMapping("/generate/ppt")
    public BaseResponse<String> generatePPT(@RequestBody GeneratePPTAddRequest generatePPTAddRequest, HttpServletRequest request) {
        //1.校验参数
        ThrowUtils.throwIf(generatePPTAddRequest == null, ErrorCode.PARAMS_ERROR);
        Long id = generatePPTAddRequest.getId();
        String templateId = generatePPTAddRequest.getTemplateId();
        ThrowUtils.throwIf(id <= 0, ErrorCode.PARAMS_ERROR);
        //2. 根据id 查询到生成PPT大纲的实体类
        GeneratePpt generatePptServiceById = generatePptService.getById(id);
        ThrowUtils.throwIf(generatePptServiceById == null, ErrorCode.NOT_FOUND_ERROR);
        CreateByOutlineRequest createByOutlineRequest = new CreateByOutlineRequest();
        String outline = generatePptServiceById.getOutline();
        ThrowUtils.throwIf(outline == null, ErrorCode.PARAMS_ERROR);
        //3.封装生成ppt请求对象
        createByOutlineRequest.setOutline(JSONUtil.parseObj(outline));
        createByOutlineRequest.setQuery(PROMPT_TEMPLATE);
        createByOutlineRequest.setTemplateId(templateId);
        createByOutlineRequest.setAuthor(generatePptServiceById.getUserName());

        // 4. PPT生成 （通过大纲生成PPT）
        String resp1 = null;
        try {
            resp1 = apiClient.createPptByOutline(createByOutlineRequest);
        } catch (IOException e) {
            log.error("fail to generate ppt ");
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "ppt生成失败");
        }
        //5.查询进度
        // 5.1根据PPT生成接口返回的sid，得到最终PPT的下载链接
        CreateResponse pptResponse = JSON.parseObject(resp1, CreateResponse.class);
        String sid = pptResponse.getData().getSid();
        generatePptServiceById.setSid(sid);
        generatePptServiceById.setCoverImgSrc(generatePPTAddRequest.getCoverImgSrc());
        generatePptServiceById.setTitle(pptResponse.getData().getTitle());//再次设置标题
        boolean saveOrUpdate = generatePptService.saveOrUpdate(generatePptServiceById);
        ThrowUtils.throwIf(!saveOrUpdate, ErrorCode.SYSTEM_ERROR, "sid更新失败");
        //返回 sid
        return ResultUtils.success(sid);
    }

    /**
     * 获取生成进度  前端轮询接口
     * @param sid 任务id
     * @return pptUrl
     */
    @PostMapping("/check/progress")
    @Deprecated
    public BaseResponse<String> checkProgress(@RequestParam("sid") String sid) {
        String jsonProgressResponse = null;
        try {
            //调用 apiClient 查询sid
            jsonProgressResponse = apiClient.checkProgress(sid);
        } catch (IOException e) {
            log.error("fail to get the generation progress ,the reason is:" + e.getMessage());
        }
        //解析json字符串
        ProgressResponse progressResponse = JSON.parseObject(jsonProgressResponse, ProgressResponse.class);
        ProgressResponse.Data data = progressResponse.getData();
        String pptUrl = data.getPptUrl();
        String pptStatus = data.getPptStatus();
        //创建updateWrapper
        UpdateWrapper<GeneratePpt> generatePptUpdateWrapper = new UpdateWrapper<>();
        if (Objects.equals(GeneratePptStatusEnum.getValueByText(pptStatus), GeneratePptStatusEnum.DONE.getValue())) {
            log.info("The ppt has been generated successfully, the ppt url is {}", pptUrl);
            generatePptUpdateWrapper.set("status", GeneratePptStatusEnum.DONE.getValue());
        }
        generatePptUpdateWrapper.set("pptUrl", pptUrl).eq("sid",sid);
        generatePptService.update(generatePptUpdateWrapper);
        return ResultUtils.success(pptUrl);
    }

    /**
     * 获取生成进度
     * v2通过后端响应式请求接口 轮询
     * @param sid 任务id
     * @return pptUrl
     */
    @GetMapping("/check/progress/async")
    public BaseResponse<String> checkProgressAsync(@RequestParam("sid") String sid) {
        Mono<ProgressResponse> ProgressResponse = null;
        try {
            //调用 apiClient 查询sid
            ProgressResponse = apiClient.GenerateProgressAsync(sid);
        } catch (IOException e) {
            log.error("fail to get the generation progress ,the reason is:" + e.getMessage());
        }
            //解析json字符串
//            ProgressResponse progressResponse = JSON.parseObject(jsonProgressResponse.toString(), ProgressResponse.class);
        String pptUrl =ProgressResponse
                .publishOn(Schedulers.boundedElastic())
                .map(response -> {
                    ProgressResponse.Data data = response.getData();
                    String pptUrl1 = data.getPptUrl();
                    String pptStatus = data.getPptStatus();
                    //创建updateWrapper
                    UpdateWrapper<GeneratePpt> generatePptUpdateWrapper = new UpdateWrapper<>();
                    if (Objects.equals(GeneratePptStatusEnum.getValueByText(pptStatus), GeneratePptStatusEnum.DONE.getValue())) {
                        log.info("The ppt has been generated successfully, the ppt url is {}", pptUrl1);
                        generatePptUpdateWrapper.set("status", GeneratePptStatusEnum.DONE.getValue());
                    }
                    generatePptUpdateWrapper.set("pptUrl", pptUrl1).eq("sid",sid);
                    generatePptService.update(generatePptUpdateWrapper);
                    return data.getPptUrl();
                }).block();

        return ResultUtils.success(pptUrl);
    }

    /**
     * 获取生成进度  通过后端响应式请求接口 轮询
     * v3优化前端展示 实时显示生成进度  immediately
     *
     * @param sid 任务id
     * @return pptUrl
     */
    @GetMapping("/check/progress/immediately")
    public BaseResponse<CheckProgressVO> CheckProgressImmediately(@RequestParam("sid") String sid) {
        //1. 参数校验
        ThrowUtils.throwIf(StringUtils.isBlank(sid), ErrorCode.PARAMS_ERROR);
        //2. 调用服务层 逻辑
        CheckProgressVO checkProgressVO = generatePptService.getCheckProgressVOImmediately(sid);
        //3. 返回结果
        return ResultUtils.success(checkProgressVO);
    }

    @PostMapping("/list/page/vo")
    public BaseResponse<Page<GeneratePptVO>> listGeneratePptVOByPage(@RequestBody GeneratePptQueryRequest generatePptQueryRequest
            , HttpServletRequest request) {
        //1.校验参数
        ThrowUtils.throwIf(generatePptQueryRequest == null, ErrorCode.PARAMS_ERROR);
        int current = generatePptQueryRequest.getCurrent();
        int pageSize = generatePptQueryRequest.getPageSize();
        User loginUser = userService.getLoginUser(request);
        generatePptQueryRequest.setUserName(loginUser.getUserName());
        Page<GeneratePpt> generatePptPage = generatePptService.page(new Page<>(current, pageSize)
                , generatePptService.getGeneratePptQueryWrapper(generatePptQueryRequest));
        Page<GeneratePptVO> generatePptVOPage = new Page<>(current, pageSize, generatePptPage.getTotal());
        generatePptVOPage.setRecords(generatePptService.getGeneratePptVOList(generatePptPage.getRecords()));
        return ResultUtils.success(generatePptVOPage);

    }

}
